﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tao.OpenGl;
using PocketEngine.Lights;
using PocketEngine.Effects;
using PocketEngine.RenderTargets;
using PocketEngine.Images;
using PocketEngine.Maps;
using PocketEngine.Maths;
using PocketEngine.Engine;
using PocketEngine.Cameras;
using PocketEngine.Batches;
namespace PocketEngine.Rendering
{
    public enum pShadowQuality
    {
        Fast,Average,Good,NextGen
    }
    public class pRendererOptions
    {
        public static pShadowQuality ShadowQuality = pShadowQuality.Fast;
    }
    public class pRenderer
    {
        private pRenderTarget mRenTar;
        private pImage mShadowMap;

        public pRenderer()
        {
            int res = 0;
            mShadowMap = new pImage(pEngine.Screen.Info.Width, pEngine.Screen.Info.Height, pImageFormat.Rgba);
            mRenTar = new pRenderTarget();
        }

        public void DrawTri(pVec2 v1, pVec2 v2, pVec2 v3)
        {
            Gl.glBegin(Gl.GL_TRIANGLES);
            Gl.glVertex2f(v1.X, v1.Y);
            Gl.glVertex2f(v2.X, v2.Y);
            Gl.glVertex2f(v3.X, v3.Y);
            Gl.glEnd();
        }
        public void DrawQuad(pVec2 v1, pVec2 v2, pVec2 v3, pVec2 v4)
        {
            Gl.glBegin(Gl.GL_QUADS);
            Gl.glVertex2f(v1.X, v1.Y);
            Gl.glVertex2f(v2.X, v2.Y);
            Gl.glVertex2f(v3.X, v3.Y);
            Gl.glVertex2f(v4.X, v4.Y);
            Gl.glEnd();

        }
        /// <summary>
        /// 
        /// Draws the map.
        /// </summary>
        /// <param name="map">The map.</param>
        /// <param name="view">The view.</param>
        public void DrawMap(pMap map, pCam view)
        {
            //UpdateShadowMaps(map, view);
     
            pEffect useFx = pEngine.BuiltInEffects.BasicPointLight;
            _Draw(map, view, useFx);


           // pEngine.Pen.Image(20, 20, 400, 400, mShadowMap, pColor.White);

        }

        public void UpdateShadowMaps(pMap map, pCam view)
        {
            view.Activate();
            int tx, ty, tz;

            tx = map.TilesX;
            ty = map.TilesY;
            tz = map.TilesZ;

            float vx = view.ViewX;
            float vy = view.ViewY;





            Gl.glColor4f(0, 0, 0, 1);
            Gl.glDisable(Gl.GL_BLEND);

            foreach (var l in map.Lights)
            {
                l.Activate();
                int dx, dy, dz;
                dx = dy = dz = 0;
                pTile tile = null;
                mRenTar.Bind();
                if (l.ShadowMap == null)
                {
                    l.ShadowMap = new pImage(pEngine.Screen.Info.Width, pEngine.Screen.Info.Height, pImageFormat.Rgba);

                }
                mRenTar.AttachImage(l.ShadowMap);

                Gl.glClearColor(1, 1, 1, 1);
                Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
                Gl.glClearColor(0, 0.75f, 0.75f, 1);
                float mw = vx + pEngine.Screen.Info.Width / 2;
                float mh = vy + pEngine.Screen.Info.Height / 2;
                pVec2 mp = new pVec2(mw, mh);
                while (true)
                {

                    tile = map.Tiles[dx, dy, 0];
                    if (tile != null && tile.CastShadow)
                    {

                        tile = map.Tiles[dx, dy, 0];
                        pDrawParameters dp = new pDrawParameters();
                        dp.Material = tile.Material;

                        float rx, ry;
                        rx = (dx * map.TileWidth) - vx;
                        ry = (dy * map.TileHeight) - vy;
                        //rx+=map.TileWidth/2;
                        //ry+=map.TileHeight/2;
                        //pVec2 renPoint = pEngine.Math.TransformPoint(new pVec2(rx, ry), new pVec2(mw, mh), view.ViewRotation, view.ViewScale);
                        pVec2[] vec = new pVec2[4];
                        pVec2 midTile = pEngine.Math.TransformPoint(new pVec2(rx + map.TileWidth / 2, ry + map.TileHeight / 2), mp, view.ViewRotation, view.ViewScale);
                        vec[0] = pEngine.Math.TransformPoint(new pVec2(rx, ry), midTile, view.ViewRotation, view.ViewScale);
                        vec[1] = pEngine.Math.TransformPoint(new pVec2(rx + map.TileWidth, ry), midTile, view.ViewRotation, view.ViewScale);
                        vec[2] = pEngine.Math.TransformPoint(new pVec2(rx + map.TileWidth, ry + map.TileHeight), midTile, view.ViewRotation, view.ViewScale);
                        vec[3] = pEngine.Math.TransformPoint(new pVec2(rx, ry + map.TileHeight), midTile, view.ViewRotation, view.ViewScale);
                        //       foreach (var l in map.Lights)
                        //         {
                        pVec2 nL = pEngine.Math.TransformPoint(new pVec2(l.Position.X, l.Position.Y), mp, view.ViewRotation, view.ViewScale);
                        pVec2[] tar = new pVec2[4];


                        ProjectPoint(vec, nL, tar, 0);
                        ProjectPoint(vec, nL, tar, 1);
                        ProjectPoint(vec, nL, tar, 2);
                        ProjectPoint(vec, nL, tar, 3);

                        DrawQuad(vec[3], vec[0], tar[0], tar[3]);
                        DrawQuad(vec[0], vec[1], tar[1], tar[0]);
                        DrawQuad(vec[1], vec[2], tar[2], tar[1]);
                        DrawQuad(vec[3], vec[2], tar[2], tar[3]);
                        DrawQuad(vec[0], vec[1], vec[2], vec[3]);
                        //'DrawTri(vec[0], tar[0], vec[1]);
                        //DrawTri(vec[1], tar[1], tar[0]);
                        //DrawTri(vec[3], vec[0], tar[0]);
                        //DrawTri(vec[3], tar[3], tar[0]);
                        //DrawTri(vec[1], vec[2], tar[1]);
                        //DrawTri(vec[2], tar[2], tar[1]);
                        //DrawTri(vec[3], vec[2], tar[3]);
                        //DrawTri(vec[3], tar[2], tar[3]);


                        //pVec3 oldPos = l.Position;
                        //l.Position = new pVec3(nL.X, nL.Y, oldPos.Z);
                        //l.Activate();

                        //]           }
                    }

                    dx += 1;
                    if (dx == tx)
                    {
                        dx = 0;
                        dy += 1;
                        if (dy == ty)
                        {
                            break;
                        }
                    }

                }

                mRenTar.Unbind();

            }
            Gl.glEnable(Gl.GL_BLEND);
        }

        private static void ProjectPoint(pVec2[] vec, pVec2 nL, pVec2[] tar, int tarIndex)
        {
            float xd, yd;
            xd = nL.X - vec[tarIndex].X;
            yd = nL.Y - vec[tarIndex].Y;
            float mag = (float)Math.Sqrt((float)(xd * xd + yd * yd));
            if (mag > 0)
            {
                xd = xd / mag;
                yd = yd / mag;
                xd = xd * pLight.Active.LightRange;
                yd = yd * pLight.Active.LightRange;
            }
            tar[tarIndex] = new pVec2(vec[tarIndex].X - xd, vec[tarIndex].Y - yd);


        }
        private static void _Draw(pMap map, pCam view, pEffect useFx)
        {
            int tx, ty, tz;

            tx = map.TilesX;
            ty = map.TilesY;
            tz = map.TilesZ;

            float vx = view.ViewX;
            float vy = view.ViewY;

            pBatch batch = new pBatch();

            int dx, dy, dz;
            dx = dy = dz = 0;
            pTile tile = null;

            float mw = vx + pEngine.Screen.Info.Width / 2;
            float mh = vy + pEngine.Screen.Info.Height / 2;

            while (true)
            {

                tile = map.Tiles[dx, dy, 0];
                if (tile != null)
                {

                    tile = map.Tiles[dx, dy, 0];
                    pDrawParameters dp = new pDrawParameters();
                    dp.Material = tile.Material;

                    float rx, ry;
                    rx = (dx * map.TileWidth) - vx;
                    ry = (dy * map.TileHeight) - vy;
                    //rx+=map.TileWidth/2;
                    //ry+=map.TileHeight/2;
                    pVec2 renPoint = pEngine.Math.TransformPoint(new pVec2(rx, ry), new pVec2(mw, mh), view.ViewRotation, view.ViewScale);
                    batch.Add(new pRenderBatchItem(tile.Visual[0], dp, map.Lights, useFx));

                    dp.X = renPoint.X - 3;
                    dp.Y = renPoint.Y - 3;
                    dp.Z = 0;
                    dp.Width = map.TileWidth + 6;
                    dp.Height = map.TileHeight + 6;
                    dp.Scale = view.ViewScale;
                    dp.Rotation = view.ViewRotation;
                    dp.TakeShadow = tile.TakeShadow;
                }

                dx += 1;
                if (dx == tx)
                {
                    dx = 0;
                    dy += 1;
                    if (dy == ty)
                    {
                        break;
                    }
                }

            }

            batch.Sort();
            batch.Run();
        }

    }
}
